﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SuperKit {
    
    /// <summary>
    /// 简单型的线程。有几个线程，就把传入的项目分成几个组。然后分别检查执行。
    /// 这个多线程的类结构非常简单，但是也有其弊端，就是每个组执行的速度不是均匀的。
    /// 如果有3个线程，1，2组的执行完了，3组还没有执行完，那么3组剩下的也不会分为几个线程执行。
    /// 本来我有一个非常先进的ThreadTool，但是老是感觉不好用。
    /// </summary>
    /// <typeparam name="T">泛型项目</typeparam>
    public class SimpleThreadExecutor<T> {
        private const int STATE_READY = 0;
        private const int STATE_RUNNING = 1;
        private const int STATE_FINISHED = 2;

        private class Item {
            public int state;
            public T item;

            public Item(T item) {
                this.state = STATE_READY;
                this.item = item;
            }
        }

        public delegate void OnAction(T item);
        public delegate void OnComplete();

        public List<T> Items { get; }
        public int ThreadCount { get; }

        private List<Item> ProcessItems { get; set; }
        private OnAction ExecuteAction { get; set; }
        private OnComplete CompleteCallback { get; set; }

        public SimpleThreadExecutor(List<T> items, int thread) {
            Items = items;
            this.ThreadCount = thread;
        }

        public SimpleThreadExecutor(int thread) {
            Items = new List<T>();
            ThreadCount = thread;
        }

        public void Add(T item) {
            Items.Add(item);
        }

        /// <summary>
        /// 启动线程的执行。
        /// </summary>
        /// <param name="executeAction">对每一个项目需要执行的处理过程</param>
        /// <param name="callback">所有项目完成之后的回调方法</param>
        public void Start(OnAction executeAction, OnComplete callback) {
            ExecuteAction = executeAction;
            CompleteCallback = callback;

            ProcessItems = new List<Item>();
            foreach (var i in Items) {
                ProcessItems.Add(new Item(i));
            }

            Thread t = new Thread(OnRun);
            t.Start();
        }

        private void OnRun() {
            while (true) {
                if (GetStateCount(STATE_FINISHED) == ProcessItems.Count) {
                    break;
                }

                CheckStart();

                Thread.Sleep(50);
            }

            CompleteCallback?.Invoke();
        }

        private void CheckStart() {
            if (GetStateCount(STATE_RUNNING) >= ThreadCount) {
                return;
            }
            foreach (var item in ProcessItems) {
                if (item.state == STATE_READY) {
                    StartItem(item);
                    return;
                }
            }

        }

        private void StartItem(Item item) {
            item.state = STATE_RUNNING;
            Thread t = new Thread(() => {
                ExecuteAction(item.item);
                item.state = STATE_FINISHED;
            });
            t.Start();
        }

        public int GetStateCount(int state) {
            int count = 0;
            foreach (var i in ProcessItems) {
                if (i.state == state) {
                    count++;
                }
            }
            return count;
        }

        public int GetFinished() {
            return GetStateCount(STATE_FINISHED);
        }

        public int GetRunning() {
            return GetStateCount(STATE_RUNNING);
        }

        public string GetFinishString(bool plus) {
            // 这里的+1是因为调用这个项目的时候，通常处于ExecuteAction中，
            // 而在回调方法中，已经执行完成了。但是Finish的标志还没有打上。所以需要额外+1.
            return string.Format("{0}/{1}", GetFinished() + (plus ? 1 : 0), Items.Count);
        }

        public string GetProcessString() {
            // 这里的加表示当前要执行的项目，因为这个方法显示的是当前/总量
            return string.Format("{0}/{1}", GetFinished() + GetRunning(), Items.Count);
        }
    }
}
